<?php

/**
 * 常用工具库
 */

namespace util;

class Util {

	/**
	 * 生成UUID
	 * @param  string $value 待解密字符串
	 * @return string
	 */
	public function getId() {
        if (function_exists('uuid_create') && !function_exists('uuid_make')) {
            $id = uuid_create(UUID_TYPE_DEFAULT);
        } elseif (function_exists('com_create_guid')) {
            $id = strtolower(trim(com_create_guid(), '{}'));
        } else {
            $id = $this->createId();
        }
        return $id;
    }

    /**
     * 创建UUID
     * @return string
     */
    protected function createId() {
        $salt = substr(hash('sha256', microtime(true) . mt_rand()), 0, 64);
        $hex  = substr(hash('sha256', $salt), 0, 32);
        $time_low = substr($hex, 0, 8);
        $time_mid = substr($hex, 8, 4);
        $time_hi_and_version = base_convert(substr($hex, 12, 4), 16, 10);
        $time_hi_and_version &= 0x0FFF;
        $time_hi_and_version |= (4 << 12);
        $clock_seq_hi_and_reserved = base_convert(substr($hex, 16, 4), 16, 10);
        $clock_seq_hi_and_reserved &= 0x3F;
        $clock_seq_hi_and_reserved |= 0x80;
        $clock_seq_low = substr($hex, 20, 2);
        $nodes = substr($hex, 20);
        $uuid  = sprintf('%s-%s-%04x-%02x%02x-%s',
                    $time_low, $time_mid,
                    $time_hi_and_version, $clock_seq_hi_and_reserved,
                    $clock_seq_low, $nodes
                );

        return $uuid;
    }

     /**
     * 验证是否符合uuid规范
     */
    public function isId($uuid) {
        return preg_match("/^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$/", $uuid);
    }
    
	/**
	 * HTML代码过滤
	 * @param  string $str 字符串
	 * @return string
	 */
	public static function escapeHtml($str){
		$search = array ("'<script[^>]*?>.*?</script>'si",  // 去掉 javascript
						 "'<iframe[^>]*?>.*?</iframe>'si", // 去掉iframe
						);
		$replace = array ("","",);		
		$str = preg_replace ($search, $replace, $str);
		$str = htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
	   return $str;
	}

    /**
     * 转换html实体编码
     *
     * @param string $str
     * @return string
     */
    public static function convertTags($str){
        return str_replace(array('<', '>', "'", '"'), array('&lt;', '&gt;', '&#039;', '&quot;'), $str);
    }

	/**
	 * 获取来访IP
	 * @return string
	 */
	public static function getIp(){
        $ip = null;
        if (getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')){
            $ip = getenv('HTTP_CLIENT_IP');
        } elseif (getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')){
            $ip = getenv('HTTP_X_FORWARDED_FOR');
        } elseif (getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')){
            $ip = getenv('REMOTE_ADDR');
        } elseif (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'],'unknown')){
            $ip = $_SERVER['REMOTE_ADDR'];
        }else{
            $ip = '0.0.0.0';
        }
        //是否是一个合法的ip地址
        return (false !== ip2long($ip)) ? $ip : '0.0.0.0';
	}

    /**
     * 返回IP的整数形式
     *
     * @param string $ip
     * @return string
     */
    public static function getLongIp($ip = ''){
        if ($ip == '') {
            $ip = self::getIp();
        }

        return sprintf("%u", ip2long($ip));
    }

	/**
	 * 中英文字符串截取
	 * @param  string  $str     字符串
	 * @param  integer $start   起始长度
	 * @param  integer $length  截取长度
	 * @param  string  $charset 字符编码
	 * @param  boolean $suffix  截取后缀
	 * @return string
	 */
	public static function msubstr($str, $start = 0, $length, $charset="utf-8", $suffix = true){
		if($charset!='utf-8'){
            $str = mb_convert_encoding($str,'utf8',$charset);
        }
        $osLen = mb_strlen($str);
        if($osLen <= $length){
            return $str;
        }
        $string = mb_substr($str,$start,$length,'utf8');
        $sLen = mb_strlen($string,'utf8');
        $bLen = strlen($string);
        $sCharCount = (3*$sLen-$bLen)/2;
        if($osLen<=$sCharCount+$length){
            $arr = preg_split('/(?<!^)(?!$)/u',mb_substr($str,$length+1,$osLen,'utf8')); //将中英混合字符串分割成数组（UTF8下有效）
        }else {
            $arr = preg_split('/(?<!^)(?!$)/u',mb_substr($str,$length+1,$sCharCount,'utf8'));
        }
        foreach($arr as $value){
            if(ord($value)<128 && ord($value)>0){
                $sCharCount = $sCharCount-1;
            }else {
                $sCharCount = $sCharCount-2;
            }
            if($sCharCount<=0){
                break;
            }
            $string.=$value;
        }
        return $string;
		if($suffix) return $string."…";
		return $string;
	}

	/**
	 * 判断UTF-8
	 * @param  string  $string 字符串
	 * @return boolean
	 */
	public static function isUtf8($string){
		if( !empty($string) ) {
			$ret = json_encode( array('code'=>$string) );
			if( $ret=='{"code":null}') {
				return false;
			}
		}
		return true;
	}

	/**
	 * 字符串转码
	 * @param  string $fContents 字符串
	 * @param  string $from      原始编码
	 * @param  string $to        目标编码
	 * @return string
	 */
	public static function auto_charset($fContents,$from='gbk',$to='utf-8'){
		$from   =  strtoupper($from)=='UTF8'? 'utf-8':$from;
		$to       =  strtoupper($to)=='UTF8'? 'utf-8':$to;
		if( strtoupper($from) === strtoupper($to) || empty($fContents) || (is_scalar($fContents) && !is_string($fContents)) ){
			//如果编码相同或者非字符串标量则不转换
			return $fContents;
		}
		if(is_string($fContents) ) {
			if(function_exists('mb_convert_encoding')){
				return mb_convert_encoding ($fContents, $to, $from);
			}elseif(function_exists('iconv')){
				return iconv($from,$to,$fContents);
			}else{
				return $fContents;
			}
		}
		elseif(is_array($fContents)){
			foreach ( $fContents as $key => $val ) {
				$_key =     self::auto_charset($key,$from,$to);
				$fContents[$_key] = self::auto_charset($val,$from,$to);
				if($key != $_key )
					unset($fContents[$key]);
			}
			return $fContents;
		}
		else{
			return $fContents;
		}
	}

	/**
	 * 加密函数
	 * @param  mixed   $data   加密数据
	 * @param  string  $key    密匙
	 * @param  integer $expire 失效时间
	 * @return string
	 */
	public static function cpEncode($data, $key='', $expire = 0){
		$string=serialize($data);
		$ckey_length = 4;
		$key = md5($key);
		$keya = md5(substr($key, 0, 16));
		$keyb = md5(substr($key, 16, 16));
		$keyc = substr(md5(microtime()), -$ckey_length);

		$cryptkey = $keya.md5($keya.$keyc);
		$key_length = strlen($cryptkey);
		
		$string =  sprintf('%010d', $expire ? $expire + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
		$string_length = strlen($string);
		$result = '';
		$box = range(0, 255);

		$rndkey = array();
		for($i = 0; $i <= 255; $i++) {
			$rndkey[$i] = ord($cryptkey[$i % $key_length]);
		}

		for($j = $i = 0; $i < 256; $i++) {
			$j = ($j + $box[$i] + $rndkey[$i]) % 256;
			$tmp = $box[$i];
			$box[$i] = $box[$j];
			$box[$j] = $tmp;
		}

		for($a = $j = $i = 0; $i < $string_length; $i++) {
			$a = ($a + 1) % 256;
			$j = ($j + $box[$a]) % 256;
			$tmp = $box[$a];
			$box[$a] = $box[$j];
			$box[$j] = $tmp;
			$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
		}
		return $keyc.str_replace('=', '', base64_encode($result));		
	}

	/**
	 * 解密函数
	 * @param  string $string 加密字符串
	 * @param  string $key    密匙
	 * @return mixed
	 */
	public static function cpDecode($string,$key=''){
		$ckey_length = 4;
		$key = md5($key);
		$keya = md5(substr($key, 0, 16));
		$keyb = md5(substr($key, 16, 16));
		$keyc = substr($string, 0, $ckey_length);
		
		$cryptkey = $keya.md5($keya.$keyc);
		$key_length = strlen($cryptkey);
		
		$string =  base64_decode(substr($string, $ckey_length));
		$string_length = strlen($string);
		
		$result = '';
		$box = range(0, 255);

		$rndkey = array();
		for($i = 0; $i <= 255; $i++) {
			$rndkey[$i] = ord($cryptkey[$i % $key_length]);
		}

		for($j = $i = 0; $i < 256; $i++) {
			$j = ($j + $box[$i] + $rndkey[$i]) % 256;
			$tmp = $box[$i];
			$box[$i] = $box[$j];
			$box[$j] = $tmp;
		}

		for($a = $j = $i = 0; $i < $string_length; $i++) {
			$a = ($a + 1) % 256;
			$j = ($j + $box[$a]) % 256;
			$tmp = $box[$a];
			$box[$a] = $box[$j];
			$box[$j] = $tmp;
			$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
		}
		if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
			return unserialize(substr($result, 26));
		}else{
			return '';
		}	
	}

	/**
	 * 删除目录所有文件
	 * @param  string $dir 路径
	 * @return boolean
	 */
	public static function delDir($dir){
		if (!is_dir($dir)){
			return false;
		}
		$handle = opendir($dir);
		while (($file = readdir($handle)) !== false){
			if ($file != "." && $file != ".."){
				is_dir("$dir/$file")? self::delDir("$dir/$file") : @unlink("$dir/$file");
			}
		}
		if (readdir($handle) == false){
			closedir($handle);
			@rmdir($dir);
		}
        return true;
	}

    /**
     * 根据文件名创建文件
     *
     * @param string $file_name
     * @param int $mode
     * @return bool
     */
    public static function mkfile($file_name, $mode = 0775){
        if (!file_exists($file_name)) {
            $file_path = dirname($file_name);
            self::createFolders($file_path, $mode);
            $fp = fopen($file_name, 'w+');
            if ($fp) {
                fclose($fp);
                chmod($file_name, $mode);
                return true;
            }
            return false;
        }
        return true;
    }

    /**
     * 创建文件夹
     *
     * @param string $path
     * @param int $mode
     */
    public static function createFolders($path, $mode = 0755){
        if (!is_dir($path)) {
            mkdir($path, $mode, true);
        }
    }

	 /**
     * 显示友好时间格式
     *
     * @param int $time 时间戳
     * @param string $format
     * @param int $start_time
     * @param string $suffix
     * @return string
     */
    public static function ftime($time, $format = 'Y-m-d H:i:s', $start_time = 0, $suffix = '前'){
        if ($start_time == 0) {
            $start_time = time();
        }
        $t = $start_time - $time;
        if ($t < 63072000) {
            $f = array(
                '31536000' => '年',
                '2592000' => '个月',
                '604800' => '星期',
                '86400' => '天',
                '3600' => '小时',
                '60' => '分钟',
                '1' => '秒'
            );

            foreach ($f as $k => $v) {
                if (0 != $c = floor($t / (int)$k)) {
                    return $c . $v . $suffix;
                }
            }
        }
        return date($format, $time);
    }

    /**
     * 格式化数据大小(单位byte)
     *
     * @param int $size
     * @return string
     */
    public static function convert($size){
        $unit = array('b', 'kb', 'mb', 'gb', 'tb', 'pb');
        $s = floor(log($size, 1024));
        $i = (int)$s;

        if (isset($unit[$i])) {
            return sprintf('%.2f ' . $unit[$i], $size / pow(1024, $s));
        }
        return $size . ' ' . $unit[0];
    }

    /**
     * 取得文件扩展名
     *
     * @param string $file 文件名
     * @return string
     */
    public static function getExt($file){
        $file_info = pathinfo($file);
        return $file_info['extension'];
    }

    /**
     * html转换字符串
     * @param  string $field 字段名/HTML内容
     * @param  type   $type 字段类型
     * @return string
     */
    public static function htmlEncode($data){
        return htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
    }

    /**
     * 字符串转换html
     * @param  string $field 字段名/HTML内容
     * @param  type   $type 字段类型
     * @return string
     */
    public static function htmlDecode($data){
        return html_entity_decode($data, ENT_QUOTES, 'UTF-8');
    }

    /**
     * 清理HTML
     * @param  string $field 字段名/HTML内容
     * @param  type   $type 字段类型
     * @return string
     */
    public static function filterHtml($data){
        $html = self::htmlDecode($data);
    } 
}